#!/usr/bin/perl
# 2014/06/22 count entire possible combination of fix 3kb bins
# 2014/06/20 count number of all possible HindIII combinations

use strict;
use warnings;
use IO::File;
use Getopt::Std;
use Carp qw(croak);
$| = 0;



use threads;
use Thread::Semaphore;
use threads::shared;
use Thread::Queue;

my %Len_chr = (
	'I'	=>	5579133,
	'II'	=>	4539804,
	'III'	=>	2452883,
	'chr1' => 5672121,
	'chr2' => 4615470,
	'chr3' => 2493767
);


my %Bins;
#foreach my $chr(qw(I II III)){
foreach my $chr(qw(chr1 chr2 chr3)){
#	for(my $i = 250; $i < $Len_chr{$chr}-250; $i += 500){
	for(my $i = 2500; $i < $Len_chr{$chr}-2500; $i += 5000){
#	for(my $i = 2500 + 500000; $i < $Len_chr{$chr}-2500 - 500000; $i += 5000){	# without telomere combination
		push @{$Bins{$chr}}, $i;
	}
}



my $THREAD_NUMBER = 30;
my $semaphore_ONOFF = Thread::Semaphore->new(1);
my $distanceQue = Thread::Queue->new();


my %distance :shared;

my @threads;
for(1 .. $THREAD_NUMBER){
	my ($thread) = new threads(\&calc_distance);	# () is important to return %hash !!!!
	push @threads, $thread;
}

#foreach my $chr(qw(I II III)){
foreach my $chr(qw(chr1 chr2 chr3)){
	my @lists = @{$Bins{$chr}};
	for(my $i = 0; $i < @lists; $i++){
		my $one_side = $lists[$i];
		for(my $j = $i + 1; $j < @lists; $j++){
			my $other_side = $lists[$j];
			$distanceQue->enqueue("$one_side\t$other_side");
		}
	}
}

# to stop the threads
for(1 .. $THREAD_NUMBER){
	$distanceQue->enqueue(undef);	# distanceQue->end() was not worked.
}


### wait until all thread will finish
foreach (@threads){
	$_->join();
}

#---------------------------------------
# output
#---------------------------------------
foreach my $d(sort { $a <=> $b} keys %distance){
	print "$d\t$distance{$d}\n";
}


sub calc_distance{
	my %hash;
	while(my $data = $distanceQue->dequeue()){
		my ($one_side, $other_side) = split /\t/, $data;
		my $distance = abs($one_side - $other_side);
		my $cate = int($distance / 5000) * 5000;
		$hash{$cate}++;
	}
	$semaphore_ONOFF->down();
	foreach my $key(keys %hash){
		if(exists $distance{$key}){
			$distance{$key} += $hash{$key};
		}else{
			$distance{$key} = $hash{$key};
		}
	}
	$semaphore_ONOFF->up();
	threads->yield();
}

